🛤️

FilCDN M3 Usage-based payments

💡

Changelog

  • 12.08.2025.
    • Changed egress quota model from per-data-set to per-user model
    • Added a FilCDN Verifier contract to the architecture and renamed previous usage of the term "verifier" to "validator"
  • 13.08.2025.
    • Updated pricing model from usage-based to combination of streaming and usage-based model (hybrid)
  • 10.09.2025.
    • Reverted back to from hybrid (usage-based & streaming) model to usage-based model

GitHub issues

Overview

This document outlines the basic payment flows and architecture for FilCDN in alignment with a new usage-based pricing model.

We assume that the system will continue to support two separate payment rails: one for cache misses and another for cache hits. Each rail will be compensated proportionally to the amount of egress it serves. This assumption also implies that users would need to maintain separate funding for each payment rail, effectively enabling CDN functionality on a per-data-set basis rather than for the entire account.

Finally, it is assumed that the price of both cache-hit and cache-miss egress is the same amount.

Glossary

  • Payment Rail – The channel through which payments flow from the payer to the payee.
  • Payer – Also referred to as the user or client; the entity responsible for making payments to a service provider.
  • Payee – Also referred to as the service provider; the entity delivering services in exchange for payments from the payer.
  • Service Provider – An entity that offers services such as storage, egress, or compute to clients.
  • Storage Provider – A type of service provider specifically offering storage services.
  • Account – Tracks funds, lockups, obligations, and related activities associated with an individual owner. Both payers and payees maintain accounts.
  • Verifier – A smart contract responsible for verifying proofs or data submitted by a service provider.
  • Validator – A smart contract responsible for validating settlement amounts across payment rails.
  • Settlement (Rail Settlement) – The process of calculating the payment amount for a defined period, based on pre-determined parameters, and transferring funds from the payer to the payee.
  • Operator - Performs operations over payment rails (rate and lockup modification, termination, etc.).
  • Service contract – A smart contract responsible for delivering a defined service (e.g., the Filecoin Warm Storage Service). In practice, it often fulfills the dual role of validator and operator.
  • Lockup – Funds reserved by the payer to guarantee future obligations. See more on lockups here.
  • Fixed Lockup – Funds reserved by the payer to cover one-time payments.

Background

The existing payment model is based on a flat fee structure where users pay a fixed amount for unlimited access to CDN services. While this model simplifies billing, it introduces inefficiencies and misaligned incentives.

The current payment architecture relies on the two main components:

  • Filecoin Warm Storage Service (FWSS) contract
  • Payments contract

These two components facilitate the creation, settlement and termination of payment rails — each payment rail corresponding to a specific service category such as storage, cache-hit, or cache-miss egress.

Payment (settlement) logic for these payment rails is primarily based on a pre-calculated per-epoch rate, which is not well-suited to dynamic or usage-based pricing schemas.

Proposed Payment Model

The proposal introduces usage-based pricing model, where users are charged based on the volume of data egressed from the network.

Unlike the current streaming payment models with pre-calculated payment rates, this new model extends functionality with usage-based rate calculation.

The price is expressed as cost per TiB of egress (e.g., $10/TiB per month) and is calculated during the settlement period. In the initial phase, egress price for cache-hit and cache-miss egress will be the same.

Key features of new payment model include:

  • Pre-calculated Monthly Rate – When a CDN payment rail is created, it is assigned a fixed monthly price per TiB of egress (e.g., $10/TiB/month).
  • Streaming Payments – The rail continually settle payments over time based on pre-calculated rate, even if no egress is served during the period.
  • Usage-Based Pricing – If egress usage is recorded for the period, settlement amount is based on the amount of bytes served × the $/TiB rate.

This change requires accurate metering of egress, timely settlement mechanisms, and a way to associate payments rails with usage stats. The remainder of this document outlines how this will be achieved and the architectural changes necessary to support it.

Architectural Changes


While transitioning to a usage-based payment model does need several architectural changes in order to ensure correct settlement logic, our main goal remains that core components such as the Filecoin Warm Storage Service (FWSS) and Payment contract have minimal changes.

Component changes

  • FilCDN Verifier Contract
    This contract serves as a central component for storing per-data-set egress usage reported by the FilCDN off-chain worker. During each egress usage report submission, the contract calls the FilCDN validator, which acts as a listener. This contract lacks knowledge about payments and payment rails.
  • FilCDN Validator Contract
    Acts as a listener
    contract to the verifier contract and is triggered when egress usage reports are submitted. When called by the verifier contract, it splits the per-data-set usage data and maps it to appropriate payment rails. This contract handles accounting for both CDN (cache-hit) and cache-miss payment rails. During settlement, these payment rails call the validator contract, which calculates and returns the settlement amount.
  • FilCDN Off-Chain Worker
    This worker is responsible for tracking and reporting egress usage. It periodically submits aggregated egress usage data for each data set to the FilCDN verifier Contract.
  • FWSS Service Rail Creation
    To ensure correct settlement of cache-miss and CDN (cache-hit) payment rails, we need to update the current rail creation logic. This update will create new rails that use the newly added FilCDN validator contract as a payment validator.
  • FilCDN Validator Rail Settlement
    Although the rail settlement logic would not change, these newly created rails would call the FilCDN validator with specified start and end epochs, and a constant representing streaming payment rate. The validator contract would observe usage data over the given period. If the validator has data for the specified time period with no usage observed, it would return some kind of error. However, if egress usage is observed, the validator contract would calculate the correct amount based on the actual usage between the two epochs.
  • FWSS Top-up mechanism
    In order to enable egress top-up we’d need to add a new method to the FWSS contract. This method would allow users to increase top-up their egress by increasing their fixed lockup.

Payment Flows

This section outlines basic payment flows and how the prepayments and usage-based settlement will function under the new architecture.

Cache-Hit & Cache-Miss Rail Creation

  1. User creates a data set with CDN service enabled
  1. Filecoin Warm Storage Service creates three payment rails
    1. PDP Payment rail with validator and operator set to Filecoin Warm Storage Service
    1. CDN (Cache-Hit Payment) rail with validator set to FilCDN Validator and operator set to FWSS
    1. Cache-Miss Payment rail with validator set to FilCDN Validator and operator set to FWSS
  1. User locks funds by creating a fixed lockup
  1. Each payment rail (cache-hit & cache-miss) is assigned a monthly rate based on the agreed pricing (e.g., $10/TiB of egress per month).

Cache-Hit & Cache-Miss Rail Settlement

  1. A scheduled job or triggered process aggregates usage data based by the epoch and submits the result to FilCDN Verifier Contract.
  1. FilCDN Verifier Contract calls the FilCDN Validator Contract with aggregated egress usage data. The Validator Contract then splits this data for each payment rail and stores it in the contract.
  1. A storage provider or a service (FilCDN) triggers the settlement process for the payment rail
  1. Payment rail performs a call to FilCDN Validator Contract with a start and end epoch they want to perform settlement for.
  1. Settlement calculation
    1. If there is no reported data for requested period (start epoch is greater then maximum available epoch), the validator should raise an error.
    1. If the rail served no egress in the period, the validator should return zero as settlement amount.
    1. If egress usage is detected, the validator calculates the settlement amount based on the available usage data.
      1. If data is available for the requested period, the validator calculates the settlement amount based on egress usage between the two epochs that define the start and end of that period.
      1. If data is only partially available (i.e., the requested end epoch is greater than the maximum available epoch), the validator calculates the settlement amount based on egress usage between the start epoch and the maximum available epoch. It then records the maximum available epoch as the latest point up to which the payment rail has been settled.
  1. The validator returns the settlement amount, along with the last epoch up to which it could settle.
  1. The payment rail updates balances accordingly.


This chart shows settlement process for both cache-miss and cache-hit (CDN) payment rail. Note that off-chain system parts are coloured in yellow while the on-chain parts are coloured blue.

Prepayment and Rail Funding

  1. Upon cache-hit and cache-miss payment rail creation streaming lockup is created based on the pre-calculated rate and lockup duration
  1. Off-chain worker observes the lockup amount alongside the user account balance and calculates the maximum egress allowance for the data set
  1. User performs changes the lockup duration extending / reducing the deal duration and increasing / decreasing the streaming lockup
  1. Off-chain worker observes user funding, recalculates the maximum egress allowance for the data set

  1. Upon CDN (cache-hit) and cache-miss payment rail creation, user creates a fixed lockup and deposits funds to the account
  1. Off-chain worker observes fixed lockup amount and account balance calculating the maximum egress allowance for the data set
  1. User performs changes to the rail fixed lockup amount and account balance
  1. Off-chain worker observes updated fixed lockup alongside the account balance and calculates updated egress allowance, saving it in the database
  1. User performs withdraw for an arbitrary amount from payment rail account
  1. Off-chain worker observes withdrawn amount and calculates updated egress allowance data set egress, saving it in the database

Toggling CDN Service (out-of-scope)

Although this payment flow is outside the scope of usage-based pricing, I've included it here since it was recently discussed.

  1. Disabling the CDN service for the data set that currently has it enabled
    In this case user would need to set streaming payment rail rate to 0. In that case settlement step would effectively be skipped.
  1. Enabling the CDN service that has previously been disabled
    In this case user would also need to
    modify streaming payment rail to non-zero arbitrary amount so the settlement step is not skipped.
  1. Enabling the CDN service for data set that did not previously have it enabled
    In this case we would either need to:
    1. Create new payment CDN (cache-hit) and cache-miss payment rails for the data set upon enabling.
    1. Create cache-hit and cache-miss payment rails upon data set creation but setting the rate to 0 effectively skipping the settlement phase.

Metering and Usage Accounting

The usage-based model relies on accurate, auditable tracking of both user balance, rail fixed lockup and egress consumption.

Each user has an egress quota limit that is derived directly from committed (locked) funds, while the egress usage is tracked and recorded off-chain, aggregated, and periodically submitted to the verifier contract for settlement.

Egress Quota Limit Derivation

💡

The egress quota limit is the maximum data the CDN can deliver for a data set, based on the user’s locked funds. Actual egress usage and limit enforcement are happening off-chain.

A egress usage quota defines how many bytes of data the CDN service can deliver per data set.

Quota limits are derived and updated based on a fixed lockup event emitted by the payment rail contract:

  • RailLockupModified – Creation or modification of a fixed lockup serving as a safety hatch for rail settlement.

Whenever RailLockupModified event is observed, the system recalculates the data set’s quota based on the lockup amount.

/// Lockup modification event (egress_quota_bytes >= 0)
egress_quota_bytes = egress_quota_bytes + lockup_amount / price_per_tib 

Additionally we should also observe deposit and withdraw events emitted by the payment rails contract:

  • DepositRecorded – Additional funds deposited into the account.
  • WithdrawRecorded – Emitted when a user withdraws funds from the account.

These events could give us an early sign into user solvency and based on them we could proactively terminate the payment rail.

As outlined in the builders guide lockup serves only as a safety hatch that’s fully utilised during the rail termination and not observing user account funds could lead us from being able to fully settle our payment rails.

Usage Aggregation & On-Chain Rollup Submission

Recorded requests are periodically aggregated off-chain into per-data-set aggregation groups.

At the end of each aggregation cycle, the rollup data is submitted to the verifier contract. It's important to note that data is not submitted to the verifier contract on each epoch, but rather periodically according to a predetermined schedule.

Upon receiving the report, the contract:

  1. Assigns the current epoch (derived from the block number) to the rollup entry.
  1. Validates the sender address (only contract owner should be able to submit rollup entry)
  1. Updates data set usage data (adds usage data to set identified by the data set id)
  1. Calls the validator contract with verified data


Data model for the verifier contract is fairly simple mapping each data set to epoch usage:

struct Usage {
    uint256 cacheHit;
    uint256 cacheMiss;
}

mapping(bytes32 dataSetId => mapping(uint256 epoch => Usage)) usageByDataSetAndEpoch;

Validator contract

The Validator contract listens for and receives aggregated usage data rollups from the verifier contract. It then splits the per-data-set usage data into cache-hit and cache-miss groups, linking the each group to the payment rail, and records the usage data against the epoch (block number) it’s submitted on. By linking per-payment-rail usage data to an on-chain epoch, we ensure accurate calculation of settled amounts for egress usage over specific time periods.

During payment validation, it computes settlement for a requested epoch window (startEpochendEpoch) using the usage it has in storage, and returns (enforces) the settlement amount.

Data model for the validator contract should be kept very simple mapping rail id to epoch usage:

  • mapping(bytes32 railId => mapping(uint256 epoch => uint256 usage)) usageByRailAndEpoch

In addition to usage data, the validator contract should also store the price (rate) in order to calculate settlement amounts based on usage history.

Validator contract - Settlement

During settlement calculation, the validator contract inspects data across the requested time window.

When the validator has data for the given period, it sums all egress usage across the requested time window, multiplying the usage by the applicable price (usage × price) and returns the settlement amount.

If the validator lacks data for part of the requested window, it sums egress usage across the available period and returns both the settlement amount and the last epoch up to which it was able to perform the calculation.

For example, if the current epoch value is 10 and the validator contract has usage data for epochs 0 to 7, while the payment rail wants to settle payments for epochs 0 to 10:

The validator contract will calculate usage for epochs 0 to 7 (the complete data available) and return epoch 7 as the end point of settlement (settleUpto = 7). The payment rail will mark epoch 7 as the last settled epoch and use it as the starting point during the next settlement period.

If the validator has no data for the given period, it should produce an error, preventing the rail from settling until the data becomes available.

NOTE: Currently validator contract is not able to return error.

Smart Contract Modifications

By introducing the FilCDN validator contract, we have minimized changes to the Filecoin Warm Storage Service contract while reusing the existing settlement logic.

The Filecoin Warm Storage Service requires the following changes to support a usage-based pricing model:

  • Adding a constant that stores FilCDN validator contract contract address.
  • Removing rate update for cache-miss and cache-hit payment rails.
  • Adding ability for validator to return error during validatePayment step

Apart from these changes additional changes to Filecoin Warm Storage Service would be required if we’d like to include ability for user to toggle CDN service on and off together with this pricing model.

Migration Strategy

TODO: Write a paragraph on how to migrate existing payment rails

Open Questions and Trade-offs

  • Should user have expiry on their egress quota (i.e. $10/TiB)?
    • If so should this quota be reset/renewed? How often should that happen? Daily could be too often and monthly too coarse grained?
  • How can we notify the user about approaching the egress quota exhaustion?
  • How to handle the case where one user has multiple data sets (multiple FWS deals paying for CDN) with different SPs. Let’s say I want to store each file with three different SPs for redundancy. Now I have to lock 3x CDN egress fee, one for each data set.
  • How to handle top-ups? Should user lock up their funds or just deposit to their account?

Future Work

This document does not address payment flows where the user retrieving the data pays for the egress. At the time of writing, we still need to conduct product exploration to develop compelling payment flows for this use case.

Future work will also focus on enabling usage reporting from multiple parties operating CDN gateways. This approach could function similarly to current blockchain rollups.